#include "mld_pch.hpp"
#include "mld.hpp"
#include "mld_impl.hpp"




// The one and only instance of the mld implementation
static mld_impl mstt;




mld::mld()
{}
///////////////////////////////////////////////////////////////////////////////////////////////////

mld::~mld()
{}
///////////////////////////////////////////////////////////////////////////////////////////////////




mld& mld::instance()
{
	return mstt;
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void* operator new(size_t size, const char* module, const char* file, const char* function, uint32 line)
{
	// ANSI says: allocation requests of 0 bytes will still return a valid value
	if(size == 0)
		size = 1;

	void* address = NULL;

	// ANSI says: loop continuously because the error handler could possibly free up some memory
	while(true)
	{
		// Try the allocation
		address = mstt.allocator(alloc::new_, size, module, file, function, line);
		if(address)
			break;

		// There isn't a way to determine the new handler, except through setting it. So we'll just set it to NULL, then
		// set it back again.
		new_handler nh = std::set_new_handler(0);
		std::set_new_handler(nh);

		// If there is an error handler, call it
		if(nh)
			(*nh)();
		else
			throw std::bad_alloc();
	}

	return address;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void* operator new[](size_t size, const char* module, const char* file, const char* function, uint32 line)
{
	// The ANSI standard says that allocation requests of 0 bytes will still return a valid value
	if(size == 0)
		size = 1;

	void* address = NULL;

	// ANSI says: loop continuously because the error handler could possibly free up some memory
	while(true)
	{
		// Try the allocation
		address = mstt.allocator(alloc::new_array, size, module, file, function, line);
		if(address)
			break;

		// There isn't a way to determine the new handler, except through setting it. So we'll just set it to NULL, then
		// set it back again.
		new_handler nh = std::set_new_handler(0);
		std::set_new_handler(nh);

		// If there is an error handler, call it
		if(nh)
			(*nh)();
		else
			throw std::bad_alloc();
	}

	return address;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void* operator new(size_t size)
{
	// ANSI says: allocation requests of 0 bytes will still return a valid value
	if(size == 0)
		size = 1;

	void* address = NULL;

	// ANSI says: loop continuously because the error handler could possibly free up some memory
	while(true)
	{
		// Try the allocation
		address = mstt.allocator(alloc::new_, size, "??", "??", "??", 0);
		if(address)
			break;

		// There isn't a way to determine the new handler, except through setting it. So we'll just set it to NULL, then
		// set it back again.
		new_handler nh = std::set_new_handler(0);
		std::set_new_handler(nh);

		// If there is an error handler, call it
		if(nh)
			(*nh)();
		else
			throw std::bad_alloc();
	}

	return address;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void* operator new[](size_t size)
{
	// The ANSI standard says that allocation requests of 0 bytes will still return a valid value
	if(size == 0)
		size = 1;

	void* address = NULL;

	// ANSI says: loop continuously because the error handler could possibly free up some memory
	while(true)
	{
		// Try the allocation
		address = mstt.allocator(alloc::new_array, size, "??", "??", "??", 0);
		if(address)
			break;

		// There isn't a way to determine the new handler, except through setting it. So we'll just set it to NULL, then
		// set it back again.
		new_handler nh = std::set_new_handler(0);
		std::set_new_handler(nh);

		// If there is an error handler, call it
		if(nh)
			(*nh)();
		else
			throw std::bad_alloc();
	}

	return address;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void* operator new(size_t size, const char* file, uint32 line)
{
	// ANSI says: allocation requests of 0 bytes will still return a valid value
	if(size == 0)
		size = 1;

	void* address = NULL;

	// ANSI says: loop continuously because the error handler could possibly free up some memory
	while(true)
	{
		// Try the allocation
		address = mstt.allocator(alloc::new_, size, "??", file, "??", line);
		if(address)
			break;

		// There isn't a way to determine the new handler, except through setting it. So we'll just set it to NULL, then
		// set it back again.
		new_handler nh = std::set_new_handler(0);
		std::set_new_handler(nh);

		// If there is an error handler, call it
		if(nh)
			(*nh)();
		else
			throw std::bad_alloc();
	}

	return address;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void* operator new[](size_t size, const char* file, uint32 line)
{
	// The ANSI standard says that allocation requests of 0 bytes will still return a valid value
	if(size == 0)
		size = 1;

	void* address = NULL;

	// ANSI says: loop continuously because the error handler could possibly free up some memory
	while(true)
	{
		// Try the allocation
		address = mstt.allocator(alloc::new_array, size, "??", file, "??", line);
		if(address)
			break;

		// There isn't a way to determine the new handler, except through setting it. So we'll just set it to NULL, then
		// set it back again.
		new_handler nh = std::set_new_handler(0);
		std::set_new_handler(nh);

		// If there is an error handler, call it
		if(nh)
			(*nh)();
		else
			throw std::bad_alloc();
	}

	return address;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void operator delete(void* address, const char* module, const char* file, const char* function, uint32 line)
{
	// ANSI says: delete & delete[] allow NULL pointers (they do nothing)
	if(address)
		mstt.deallocator(alloc::delete_, address);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void operator delete[](void* address, const char* module, const char* file, const char* function, uint32 line)
{
	// ANSI says: delete & delete[] allow NULL pointers (they do nothing)
	if(address)
		mstt.deallocator(alloc::delete_array, address);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void operator delete(void* address, const char* file, uint32 line)
{
	// ANSI says: delete & delete[] allow NULL pointers (they do nothing)
	if(address)
		mstt.deallocator(alloc::delete_, address);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void operator delete[](void* address, const char* file, uint32 line)
{
	// ANSI says: delete & delete[] allow NULL pointers (they do nothing)
	if(address)
		mstt.deallocator(alloc::delete_array, address);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void operator delete(void* address)
{
	// ANSI says: delete & delete[] allow NULL pointers (they do nothing)
	if(address)
		mstt.deallocator(alloc::delete_, address);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void operator delete[](void* address)
{
	// ANSI says: delete & delete[] allow NULL pointers (they do nothing)
	if(address)
		mstt.deallocator(alloc::delete_array, address);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
